﻿using System;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using FirstFloor.P2P;
using FirstFloor.Reversi.Controls;
using FirstFloor.Reversi.Messages;

namespace FirstFloor.Reversi
{
    public partial class Page
        : TurnBasedGame
    {
        //private Board board;
        //private ControlPanel ctrlPanel;
        private ReversiGame game;
        private PieceColor myColor;
        private PieceColor restartInitiator = PieceColor.None;
        private bool hints = true;

        public void Page_Loaded(object o, EventArgs e)
        {
            InitializeComponent();

            BrowserHost.Resize += new EventHandler(OnResize);

            board.PieceSelected += new EventHandler<LocationEventArgs>(board_PieceSelected);
            board.LinkClick += new EventHandler<EventArgs>(board_LinkClick);
            ctrlPanel.HintsClick += new EventHandler<EventArgs>(ctrlPanel_HintsClick);
            ctrlPanel.RestartClick += new EventHandler<EventArgs>(ctrlPanel_RestartClick);

            this.game = new ReversiGame(board);

            ctrlPanel.SetInfoText("Loading, please wait...");
        }

        private void OnResize(object sender, EventArgs e)
        {
            Width = BrowserHost.ActualWidth;
            Height = BrowserHost.ActualHeight;

            UpdateLayout();
        }

        private void UpdateLayout()
        {
            board.SetValue<double>(Canvas.LeftProperty, Width / 2 - board.Width / 2);
            board.SetValue<double>(Canvas.TopProperty, 50);

            ctrlPanel.SetValue<double>(Canvas.TopProperty, Height - ctrlPanel.Height - 8);
            ctrlPanel.Width = Width - 16;
        }

        private void logo_Loaded(object sender, EventArgs e)
        {
            UpdateLayout();
        }

        private void TraceMessage(string message, params object[] o)
        {
            //TextBlock block = (TextBlock)FindName("trace");
            //Run run = new Run();
            //run.Text = string.Format(message, o);

            //if (block.Inlines == null) {
            //    block.Inlines = new Inlines();
            //}
            //if (block.Inlines.Count > 10) {
            //    block.Inlines.RemoveAt(0);
            //    block.Inlines.RemoveAt(0);
            //}
            //block.Inlines.Add(run);
            //block.Inlines.Add(new LineBreak());
        }

        private void SendMessage(Message message)
        {
            SendData(message.ToString());
        }

        protected override void OnConnectionTypeChanged(P2PConnectionType type)
        {
            TraceMessage("OnConnectionTypeChanged({0})", type);
        }

        protected override void OnDataReceived(string data)
        {
            TraceMessage("OnDataReceived({0})", data);

            Message message = Message.CreateMessage(data);

            if (message is MovePieceMessage) {
                MovePieceMessage mpMessage = (MovePieceMessage)message;

                MovePiece(mpMessage.X, mpMessage.Y, this.game.GetOppositeColor(this.myColor));
            }
            else if (message is RestartMessage){
                if (this.restartInitiator == this.myColor) {
                    StartGame(GameStartedWithMyTurn);
                }
                else {
                    ctrlPanel.SetInfoText("Opponent requests a game restart. Press 'Restart' to confirm.");
                    this.restartInitiator = this.game.GetOppositeColor(this.myColor);
                }
            }
        }

        protected override void OnIMReceived(ref string im)
        {
            TraceMessage("OnIMReceived({0})", im);
        }

        protected override void OnSendDataError(P2PDataError error)
        {
            TraceMessage("OnSendDataError({0}, {1})", error.Type, error.Data);
        }

        protected override void OnGameStateChanged(TurnBasedGameState gameState)
        {
            TraceMessage("OnGameStateChanged({0})", gameState);

            if (gameState == TurnBasedGameState.Loaded) {
                this.myColor = Users.Me.IsInviter ? PieceColor.White : PieceColor.Red;

                StartGame(Users.Me.IsInviter);
            }
            else if (gameState == TurnBasedGameState.StartingGame) {
                this.game.InitializeGame();
            }
            else if (gameState == TurnBasedGameState.MyTurn) {
                this.restartInitiator = PieceColor.None;
                this.game.SetValidMovesSelectable(this.myColor);

                if (this.hints) {
                    this.game.MarkValidMoves(this.myColor);
                }

                ctrlPanel.SetInfoText("It's your turn");
            }
            else if (gameState == TurnBasedGameState.RemoteTurn) {
                this.restartInitiator = PieceColor.None;
                ctrlPanel.SetInfoText("Please wait for your opponent to make a move");
            }
            else if (gameState == TurnBasedGameState.GameOver) {
                string message = "it's a draw.";
                if (GameResult == TurnBasedGameResult.Won) {
                    message = "you have won!";
                }
                else if (GameResult == TurnBasedGameResult.Lost) {
                    message = "you have lost...";
                }

                ctrlPanel.SetInfoText(string.Format("Game over, {0} Press 'Restart' for a new game.", message));
            }
            else if (gameState == TurnBasedGameState.Closed) {
                if (State == P2PApplicationState.ErrorNotHostedInLiveMessenger) {
                    ctrlPanel.SetInfoText("Error: Reversi not hosted in the Live Messenger");
                }
                else if (State == P2PApplicationState.ErrorRemoteAppLoadTimeout) {
                    ctrlPanel.SetInfoText("Error: Timeout while trying to connect to remote application");
                }
                else {
                    ctrlPanel.SetInfoText("Remote has closed the application");
                }
                board.ClearMarksAndSelectables();
            }
        }

        private void board_PieceSelected(object sender, LocationEventArgs e)
        {
            if (GameState == TurnBasedGameState.MyTurn)
            {
                int x = e.Location.X;
                int y = e.Location.Y;

                if (this.game.IsValidMove(x, y, this.myColor)) {
                    MovePiece(x, y, this.myColor);
                    SendMessage(new MovePieceMessage(x, y));
                }
            }
        }

        private void board_LinkClick(object sender, EventArgs e)
        {
            OpenWindow("http://www.firstfloorsoftware.com");
        }

        private void ctrlPanel_HintsClick(object sender, EventArgs e)
        {
            this.hints = !this.hints;
            ctrlPanel.HintsText = string.Format("Hints {0}", this.hints ? "ON" : "OFF");

            if (GameState == TurnBasedGameState.MyTurn) {
                if (this.hints) {
                    this.game.MarkValidMoves(this.myColor);
                }
                else {
                    board.ClearMarks();
                }
            }
        }
        
        private void ctrlPanel_RestartClick(object sender, EventArgs e)
        {
            if (GameState == TurnBasedGameState.GameOver) {
                bool startMyTurn = GameStartedWithMyTurn;
                if (GameResult == TurnBasedGameResult.Won) {
                    startMyTurn = true;
                }
                else if (GameResult == TurnBasedGameResult.Lost) {
                    startMyTurn = false;
                }
                StartGame(startMyTurn);
            }
            else if (GameState == TurnBasedGameState.MyTurn || GameState == TurnBasedGameState.RemoteTurn){
                SendMessage(new RestartMessage());

                if (this.restartInitiator == this.game.GetOppositeColor(this.myColor)) {
                    StartGame(GameStartedWithMyTurn);
                }
                else {
                    ctrlPanel.SetInfoText("A restart request has been sent to your opponent. Please wait for confirmation.");
                    this.restartInitiator = this.myColor;
                }
            }
        }

        private void MovePiece(int x, int y, PieceColor color)
        {
            this.game.MovePiece(x, y, color);

            if (this.game.IsGameOver()){
                int myPieces = board.GetPieceCount(this.myColor);
                int remotePieces = board.GetPieceCount(this.game.GetOppositeColor(this.myColor));

                TurnBasedGameResult result = TurnBasedGameResult.Draw;
                if (myPieces > remotePieces){
                    result = TurnBasedGameResult.Won;
                }
                else if (myPieces < remotePieces){
                    result = TurnBasedGameResult.Lost;
                }

                this.StopGame(result);
            }
            else if (this.game.CanMove(this.game.GetOppositeColor(color))) {
                SwitchTurn();
            }
            else {
                // keep turn, opposite can't move
                OnGameStateChanged(GameState);
            }
        }
    }
}

